Introduction
- The research question can be summarized as: “Disentangle mechanisms
of cellular differentiation between regular stem cells and pluripotent
stem cells in mice”
- The approach used is proteomics based on MS data that was generated
in two different batches. The datasets are generated by inducing
differentiation with horse-serum on non-differentiated muscle mouse
cells (C2C12 cells) as control and blocking the differentiation by LIF
in treated sample. Proteome data set contains three control samples and
three LIF treated samples per identified protein. The Phospho data set
contains the same amount of samples from both groups, but these were
enriched for phosphorylation. This is a follow up experiment, since the
first experiment containing only the Proteome data set showed no
significant increase from any protein and the new hypothesis is based on
post-translational phosphorylation as signal.
Download raw data from Uppmax
Setting working directory and install libraries
setwd("~/phosphoproteomics_project")
RequiredPackages <- c("BiocManager", "dplyr", "igraph", "tidyr","ggplot2","ggrepel")
#Installs packages if not yet installed
for (i in RequiredPackages) {
if (!require(i, character.only = TRUE))
install.packages(i)
}
BiocManager::install(version = "3.15")
library(BiocManager)
BiocManager::install("STRINGdb")
library(tidyr)
library(dplyr)
library(igraph)
library(STRINGdb)
library(ggplot2)
library(ggrepel)
remove(RequiredPackages)
Load raw data
- Change default separator to “;”
raw_data_phospho <- read.csv(file = "~/phosphoproteomics_project/phosphoproteomics/Dataset_Phospho.csv", sep = ";")
raw_data_proteom <- read.csv(file = "~/phosphoproteomics_project/phosphoproteomics/Dataset_Proteome.csv", sep = ";")
If loop to omit na.value from all Abundance columns
- grep line selects all columns that contain the string “Abundance”
and saves the column number in Abundance_columns
- The for loop then selects all row were there is no NA value
in one of the Abundance columns and copies them to data_phospho to leave
the raw data untouched.
- !(is.na(raw_data_phospho[,i])) gives out all the
rows that don’t have an NA value, these get selected
Abundance_columns <- grep("Abundance", colnames(raw_data_phospho) )
for (i in Abundance_columns) {
data_phospho <- raw_data_phospho[!(is.na(raw_data_phospho[,i])), ]
}
Calculate Mean for Abundance and adding it as column and Ratio
LIF/Control
- grep again Abundance but this time the Control and LIF (case)
separately.
- calculate row means each and the ration between the means.
Abundance_columns <- grep("Abundance.Control", colnames(data_phospho))
data_phospho$Abudance.Mean.Control <- rowMeans(data_phospho[,c(Abundance_columns)])
Abundance_columns <- grep("Abundance.LIF", colnames(data_phospho))
data_phospho$Abudance.Mean.LIF <- rowMeans(data_phospho[,c(Abundance_columns)])
data_phospho$Abudance.Ratio <- data_phospho$Abudance.Mean.LIF / data_phospho$Abudance.Mean.Control
remove(Abundance_columns, i)
Calculate p-values
- t.test to compare all 3 Control <-> 3 Case values. If
they are different then the pvalue < 0.05 ->
indicating a real differences between case & control. If p-value is
big the difference is by chance😄 I tried it for row 188 which has a
Ration nearly equal to 1 (1.02…) indicating no difference in case
vs. control and the p value ~ 0.7 (really bad) also indicating no
difference. The for loop iterates it over all rows, Alices quicker
approach uses the apply function that allows parallel iteration making
it quicker.
start_for <- Sys.time()
for (row in 1:nrow(data_phospho)) {
p_value <- t.test(data_phospho[row,10:12], data_phospho[row,13:15], alternative = "less")
#tests if mean of control is different from mean of LIF (case) and assigns it to list p_value
data_phospho$Abudance.pvalue[row] <- p_value$p.value
#selects p.value from list and assigns it to new column"Abudance.pvalue" in the correct row
}
end_for <- Sys.time()
end_for - start_for #We wanted to compare calculation time to compare the methods
Time difference of 1.894758 secs
#Alice quicker approach
df_copy <- dplyr::tibble(data_phospho) # Copy df
start_alice <- Sys.time()
df_copy[] <- lapply(df_copy, function(x) as.numeric(as.character(x)))
df_copy$pValues <- apply(df_copy, 1, function(x) t.test(x[10:12],x[13:15], alternative = "less", paired = F)$p.value)
end_alice <- Sys.time()
end_alice-start_alice #Proves that apply is x4 faster then loop
Time difference of 0.5370486 secs
remove(end_alice,end_for,start_alice,start_for,row,p_value, df_copy)
Adding a Volcano plot to explore the initial data
- The main idea is to identify thresholds that can be used to clean
the raw data.
### Phospho volcano plot
string_db_volcano <- STRINGdb$new( version="11.5", species=10090, score_threshold=1, input_directory="")
# This had to be outside the volcano_phospho_plot function, because the function didnt return the string_db_volcano function that is needed also afterwards.
# Defining function to plot data
# Makes the whole code easy to reuse.
volcano_phospho_plot <- function(phospho, number){
# Calculate LIF/Control ratio
phospho$FC <- phospho$Abudance.Mean.LIF / phospho$Abudance.Mean.Control
phospho$log2_FC <- log2(phospho$FC)
phospho$diffexpressed <- "NO"
phospho$diffexpressed[phospho$log2_FC > 1 & phospho$Abudance.pvalue < 0.05] <- "UP" # sorts out upregulated phospo values and assigns "UP" value.
phospho$diffexpressed[phospho$log2_FC < -1 & phospho$Abudance.pvalue < 0.05] <- "DOWN" # same or downregulated phospho values
phospho$delabel <- NA
phospho$delabel[phospho$diffexpressed != "NO"] <- phospho$Master.Protein.Accessions[phospho$diffexpressed != "NO"] # selecting only up or down regulated values and assigning them to the label column.
##Addition to generate "real names" not Uniprot IDs
Mapping_phospho <- string_db_volcano$map(phospho, "delabel", removeUnmappedRows = F)
Mapping_phospho <- string_db_volcano$add_proteins_description(Mapping_phospho) #Add´s protein information to STRINGid´s = preferred names are more human readable
#Volcano plot overview
ggplot(data=Mapping_phospho, aes(x=log2_FC, y=-log10(Abudance.pvalue), col=diffexpressed, label=preferred_name))+
geom_point()+
theme_minimal()+
geom_vline(xintercept=c(-1, 1), col="red") +
geom_hline(yintercept=-log10(0.05), col="red")
#saves the correct photo for both possible input tables
# number 1 or 2 has to be defined in the function input data. This is a bit clumsy solved, but there were problems with returning more than one plot out of a function.
if (number == 1) {
ggsave("~/phosphoproteomics_project/results/Zoomed_out_Volcano.png", width = 1500, height = 1000, units = "px") # Saves plots with defined size
}
if (number == 2) {
ggsave("~/phosphoproteomics_project/results/Zoomed_out_Volcano_for_more_phosphrylated_after_qc_and_filter.png", width = 1500, height = 1000, units = "px")
}
#Detail/Zoomed in
ggplot(data=Mapping_phospho, aes(x=log2_FC, y=-log10(Abudance.pvalue), col=diffexpressed, label=preferred_name))+
geom_point()+
theme_minimal()+
geom_vline(xintercept=c(-1, 1), col="red") +
geom_hline(yintercept=-log10(0.05), col="red") +
coord_cartesian(xlim = c(1,3.5), ylim = c(0.5, 6))+
geom_label_repel()
#saves the correct photo for both possible input tables
if (number == 1) {
ggsave("~/phosphoproteomics_project/results/Zoomed_in_Volcano.png", width = 1500, height = 1000, units = "px")
}
if (number == 2) {
ggsave("~/phosphoproteomics_project/results/Zoomed_in_Volcano_for_more_phosphrylated_after_qc_and_filter.png", width = 1500, height = 1000, units = "px")
}
}
volcano_phospho_plot(data_phospho, 1) #plots data to control
trying URL 'https://stringdb-static.org/download/protein.aliases.v11.5/10090.protein.aliases.v11.5.txt.gz'
Content type 'application/octet-stream' length 13598694 bytes (13.0 MB)
==================================================
downloaded 13.0 MB
trying URL 'https://stringdb-static.org/download/protein.info.v11.5/10090.protein.info.v11.5.txt.gz'
Content type 'application/octet-stream' length 1839554 bytes (1.8 MB)
==================================================
downloaded 1.8 MB
Warning: we couldn't map to STRING 98% of your identifiers
Proteome volcano plot
- Also plotting the proteome data to identify thresholds to clean
data
# Defining function first
volcano_plot_proteome <- function(proteome){
proteome$log2_FC <- log2(proteome$Abundance.Ratio...LIF.....Control.)
proteome$diffexpressed <- "NO"
proteome$diffexpressed[proteome$log2_FC > 1 & proteome$Abundance.Ratio.P.Value...LIF.....Control. < 0.05] <- "UP"
proteome$diffexpressed[proteome$log2_FC < -1 & proteome$Abundance.Ratio.P.Value...LIF.....Control. < 0.05] <- "DOWN"
ggplot(data=proteome, aes(x=log2_FC, y=-log10(Abundance.Ratio.P.Value...LIF.....Control.), col=diffexpressed))+
geom_point()+
theme_minimal()+
geom_vline(xintercept=c(-1, 1), col="red") +
geom_hline(yintercept=-log10(0.05), col="red")
}
#Printing the volcano plot
volcano_plot_proteome(raw_data_proteom) # Plots all the data
Warning: Removed 852 rows containing missing values (geom_point).

- No values are significantly up or down regulated (defining up / down
regulated as at least 2-fold increase/decrease). Also outliers could be
observed (4 vales with a >2-fold increase with non-significant
p-values). To be more restrictive and decrease the change of false
positives in the upcoming analysis, also significantly increased values
with a ratio > 1 were selected as undesired data and are going to be
removed in the following cleaning steps.
Subsetting data_phospho for ratio values >= 2 and p-values <=
0.05
- Remove peptides without quantitative values -> Already done in
“If loop to omit na.value from all Abundance columns” thereby creating
the data_phospho
Here we use the identified thresholds from the volcano plots to
clean the data. First we select rows with ratio >= 2 and p.values
<= 0.05 from the phopho dataset. From the proteom data set values
were selected with a all rows with a ratio <= 1, all rows with a
ratio >= 1 and p.value <= 0.05 (elevated proteins (ratio >=1)
with significant p-values are excluded and protein with ratios bigger
than 2 (disregarding p-value), too). After this initial cleanup a
semi_join() was performed returning all rows from cleanup phospho with a
match in cleanup proteome, to select only phospo values that showed
increased phosphorylation due to the LIF treatment and not due to
elevated expression levels.
volcano plots were used to visualize the cleaning/selecting
steps
##Filter NA out in proteome, Filter out p.values that are non significant(not adjusted)
#securing no overwrite to original data
df_phospho = data_phospho
df_proteome = raw_data_proteom
## Filter PHOSPHO
more_phospho <- subset.data.frame(df_phospho, subset = df_phospho$Abudance.Ratio >= 2) #Filters out all ratios below 2-fold
more_phospho <- subset.data.frame(more_phospho, subset = more_phospho$Abudance.pvalue <= 0.05) #Filters out all non-significant p-values
##Filter PROTEOME
exclude_proteome <- filter(df_proteome, df_proteome$Abundance.Ratio.P.Value...LIF.....Control. <= 0.05 & df_proteome$Abundance.Ratio...LIF.....Control. >= 1) #Filters out all significant p-values, because significant p-values indicate an
#Data that we want to exclude, testing if the right data is selected with the volcano plot
volcano_plot_proteome(exclude_proteome)

#Anti_join anti_join() return all rows from x without a match in y.
more_proteome <- anti_join(df_proteome, exclude_proteome, by = c("Accession" = "Accession"))
more_proteome <- filter(more_proteome, more_proteome$Abundance.Ratio...LIF.....Control. <= 2) # removes outliers with ratio bigger then 2
#Checking the if the right data is excluded
volcano_plot_proteome(more_proteome)
#Inner join works too, but semi join is better becasue the proteome columns are not included into the resulting data frame.
#more_phosphorylated <- dplyr::inner_join( more_phospho, more_proteome, by = c("Master.Protein.Accessions" = "Accession"))
#Semi-join #semi_join() return all rows from x with a match in y.
more_phosphorylated <- dplyr::semi_join(more_phospho, more_proteome, by = c("Master.Protein.Accessions" = "Accession"))
volcano_phospho_plot(more_phosphorylated, 2) # to control remaining data

remove(df_phospho, df_proteome, more_phospho, more_proteome, exclude_proteome)
Comparing data before and after the cleanup
-we could identify that the cleanup was conducted and not too
stringent returning enough data to conduct analyisis on.


Building network map of the proteins
- With help of the STRINgdb package the overview networks were
produced with different thresholds.
##Lower score_threshold, allowing more connections
string_db_low <- STRINGdb$new(version="11.5", species=10090, score_threshold=1, input_directory="") #species = mouse identifier, score threshold = if one interaction this will be mapped, no input directory data stored only temporary
hits_low <- string_db_low$map(more_phosphorylated, "Master.Protein.Accessions", removeUnmappedRows = F) #mapping the UNIPROT Ids from the first column to get STRING identifiers
string_db_low$plot_network(hits_low$STRING_id) #plotting network

invisible(string_db_low$get_png(hits_low$STRING_id, file = "~/phosphoproteomics_project/results/Network_low.png")) #Saving photo
## Higher score_threshold, allowing less connections
string_db_high <- STRINGdb$new(version="11.5", species=10090, score_threshold=200, input_directory="") #species = mouse identifier, score threshold = if one interaction this will be mapped, no input directory data stored only temporary
hits_high <- string_db_high$map(more_phosphorylated, "Master.Protein.Accessions", removeUnmappedRows = F) #mapping the UNIPROT Ids from the first column to get STRING identifiers
string_db_high$plot_network(hits_high$STRING_id) #plotting network

invisible(string_db_high$get_png(hits_high$STRING_id, file = "~/phosphoproteomics_project/results/Network_high.png")) #Saving photo
Way to identify the Proteins Stat5b is connected to.
In this chunk we define a function with a more and a less
stringent threshold to get 1. Proteins_connected_to_Stat5b for more or
less stringent threshold, 2. Network plot for the subnetworks of
proteins connected to Stat5b, 3. Link to webpage for the subnetworks, 4.
Pathways that are enriched in the subnetworks.
There is also a link to the STRINGdb
website for less stringent threshold = 1 with the Proteins connected
to Stat5b in this dataset.
There is also a link to the STRINGdb
website for more stringent threshold = 200 with the Proteins
connected to Stat5b in this dataset.
#Finding String id identifier for Stat5b and assigning it to the a variable
i <- grep("P42232", hits_low$Master.Protein.Accessions)
Stat5b <- string_db_low$mp("P42232") #mapping the UNIPROT Ids
## Mapping Stat5b interactions in the less stringent data set and more stringent data set
#Defining a function to get 1. Proteins_connected_to_Stat5b, 2. Network plot, 3. Link to webpage, 4. Pathways
subnetworks <- function(data_h,score_h) {
#a = The data we want to have a network from, b = the threshold number of the string_db function
string_db <- STRINGdb$new(version="11.5", species=10090, score_threshold = score_h, input_directory="") #species = mouse
get <- string_db$get_subnetwork(data_h) #builds subnetwork from every entry in STRING_id
ghi <- get[[Stat5b]][1] ##gives the list entry of "get" that lists all 18 entries that interact with Stat5b
hg <- unique(ghi$`10090.ENSMUSP00000102981`) #gives the unique interaction (9 out of 18),
mat <- as_ids(ghi$`10090.ENSMUSP00000102981`) #function as_ids from the igraph package reads the class("igraph.vs") and collapses it into a matrix
Proteins_connected_to_Stat5b <- as.data.frame(unique(mat))
names(Proteins_connected_to_Stat5b)[1] <- "STRING_id" #Renaming column so that add_protein_description recognizes it
Proteins_connected_to_Stat5b[(nrow(Proteins_connected_to_Stat5b)+1),] <- Stat5b #Adds Stat5b to map its connections
Proteins_connected_to_Stat5b <- string_db$add_proteins_description(Proteins_connected_to_Stat5b) #Add´s protein information to STRINGid´s
#Plotting the subnetwork
string_db$plot_network(Proteins_connected_to_Stat5b$STRING_id)
#providing my link
link <- string_db$get_link(Proteins_connected_to_Stat5b$STRING_id) #Provides link to the STRINGdb page
#Providing the pathways
pathways <- string_db$get_enrichment(Proteins_connected_to_Stat5b, category = "KEGG")
return(list(Proteins_connected_to_Stat5b, pathways, link))
remove(get,ghi,hg,mat)
}
## Less stringent parameter to determine the Proteins that interact with Stat5
subnetwork_less_stringent <- subnetworks(data_h = hits_low$STRING_id, score_h = 1) #Using function
trying URL 'https://stringdb-static.org/download/protein.links.v11.5/10090.protein.links.v11.5.txt.gz'
Content type 'application/octet-stream' length 84569998 bytes (80.7 MB)
==================================================
downloaded 80.7 MB

#Sub-setting the returned list into original dataframes + link
Proteins_connected_to_Stat5b_less <- subnetwork_less_stringent[[1]]
pathways_less <- subnetwork_less_stringent[[2]]
Link_less <- subnetwork_less_stringent[[3]]
Link_less #Link to website
[1] "https://version-11-5.string-db.org/cgi/link?to=2E8CDC990DBD10F7"
invisible(string_db_low$get_png(Proteins_connected_to_Stat5b_less$STRING_id, file = "~/phosphoproteomics_project/results/Network_Stat5_less.png")) #Saving png
## More stringent parameter to determine the Proteins that interact with Stat5
subnetwork_more_stringent <- subnetworks(data_h = hits_high$STRING_id, score_h = 200) #Using function

#Sub-setting the returned list into original dataframes + link
Proteins_connected_to_Stat5b_more <- subnetwork_more_stringent[[1]]
pathways_more <- subnetwork_more_stringent[[2]]
Link_more <- subnetwork_more_stringent[[3]]
Link_more #Link to website
[1] "https://version-11-5.string-db.org/cgi/link?to=18B5C3E16E9B3AE0"
invisible(string_db_high$get_png(Proteins_connected_to_Stat5b_more$STRING_id, file = "~/phosphoproteomics_project/results/Network_Stat5_more.png")) #Saving png
Printing Pathways
-printing the enriched pathways from the subnetworks of Stat5b and
renaming them for a better human readability & formatting of html
document.
#Identifying only for Proteins connected to Stat5b
#Function to generate tabels based on factor gene counts / number of annotated genes.
factor_function <- function(Pathway){
i = 1
for (i in i:nrow(Pathway)) {
Pathway$factor[i] <- round((Pathway[i,3]/Pathway[i,4]), digits = 3) #rounded for better visualization
}
Pathway <- rename(Pathway, background = number_of_genes_in_background)
Pathway <- rename(Pathway, hits = number_of_genes)
Pathway <- rename(Pathway, involved_genes = preferredNames)
Pathway <- Pathway[order(Pathway$factor,decreasing = T ),]
return(print.data.frame(Pathway[1:5,c(11,3,4,10,7)], row.names = F))
}
#Table for less stringent parameters
factor_function(pathways_less)
factor hits background description involved_genes
0.054 4 74 Chronic myeloid leukemia Stat5a,Sos1,Ptpn11,Stat5b
0.045 3 66 Non-small cell lung cancer Stat5a,Sos1,Stat5b
0.043 3 70 Acute myeloid leukemia Stat5a,Sos1,Stat5b
0.041 3 74 Prolactin signaling pathway Stat5a,Sos1,Stat5b
0.037 3 81 ErbB signaling pathway Stat5a,Sos1,Stat5b
#Table for more stringent parameters
factor_function(pathways_more)
factor hits background description involved_genes
0.041 3 74 Chronic myeloid leukemia Stat5a,Ptpn11,Stat5b
0.030 3 101 AGE-RAGE signaling pathway in diabetic complications Stat5a,Foxo1,Stat5b
0.018 3 165 JAK-STAT signaling pathway Stat5a,Ptpn11,Stat5b
NA NA NA <NA> <NA>
NA NA NA <NA> <NA>
## This part does not work with STRINGdb version 11.5, it worked properly with version 11.0b
#Identifying pathways also for Proteins with a ratio >=2 and p.value <= 0.05 and threshold = 200.
#Big_network_pathways_more <- string_db_high$get_enrichment(hits_high$STRING_id, category = "KEGG")
#factor_function(Big_network_pathways_more)
#Identifying pathways also for Proteins with a ratio >=2 and p.value <= 0.05 and threshold = 1.
#Big_network_pathways_less <- string_db_low$get_enrichment(hits_low$STRING_id, category = "KEGG")
#factor_function(Big_network_pathways_less)
#remove(i, Link_less, Link_more, string_db_high, string_db_low, subnetworks, volcano_plot_proteome, subnetwork_less_stringent, subnetwork_more_stringent, hits_high, hits_low, data_phospho, factor_function, volcano_phospho_plot, string_db_volcano)
Results and Discussion
Stat5b was picked as the lead target since it showed the highest
significant ratio after data clean up in the phospho data set.
The more stringent parameters turned out less proteins connected
to Stat5b/5a but with a higher security of true association. The
generated subnetwork for Stat5b showed a very promising target for
further investigation, since a network evolved around Stat5b. Generated
pathways to investigate the effect of increased phosphorylation returned
many cancer-related pathways indicating a connection between retaining a
non-differentiated state in stem cells and the capability of cancerous
cells to form cancerous masses. Of the non-cancer pathways JAK-STAT is
of most importance since it’s also the sub pathway affected in the
cancer pathways.
The less stringent parameters turned out more proteins connected
to Stat5b/5a but has a higher risk of false positive connections. The
most important involved genes were Stat5a/b. Stat5b forms homo- and
hetero dimers with the paralog Stat5a. Upon Tyr-phosphorylation they
dimerize and translocation into the nucleus takes place, where it acts
as transcription
factor. The more stringent threshold parameter removed Sos1 from the
dataset. Sos1 is involved together with Stat5a/b in most of the enriched
pathways in the less stringent dataset. The (Ras-Raf-) MAPK pathway is
partly regulated by Sos1, normally acting as guanin nucleotide exchange
factor upon Ras.
Phosphorylation of specific Serin residues have a deactivating effect on
Sos1 and it acts as negative regulator on the whole MAPK pathway, a
pathway normally associated with promoting differentiation.
Sos1 is also involved in the mTOR pathway, together with Akt1s1 (subunit
of mTORC1), both are found in the less stringent sub network but not the
more stringent one.
Under these biological circumstances these findings can be
counted as valid and are objects for further investigations, while other
hits in the less stringent data set may be found as false positives.
This was a very good example of the trade-of encountered by threshold
settings that must be controlled thorough the data analysis.
Conclusion
- Many cancers involved pathways are also activated to ensure stemness
in non-differentiated muscle mouse cells upon differentiation
stimuli.
- Major targets for further investigations are JAK-STAT pathway
proteins and Sos1 and Akt1s1 with the mTOR- and MAPK-pathway. Especially
identification of phosphorylation sites in the protein and experiments
with different differentiation inhibitors to ensure unspecific
activation of stemness protecting pathways or identification of
alternatively activated pathways could provide more insights.
- Also, possibly a reproduction of the dataset containing more samples
to identify with a higher security the elevation of involved proteins
and also reproduction in different cell lines to ensure that the
observed effects are stemness related and not cell line related would be
interesting research targets. Since the bioinformatic pipeline is in
place, the analysis could be conducted quickly.
Reproducibility
- This project has a GitHub
repository and the Rnotebook is written so that it can be executed
with the downloaded repository.
LS0tCnRpdGxlOiAiUGhvc3Bob3Byb3Rlb21pY3MiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyBJbnRyb2R1Y3Rpb24KCi0gICBUaGUgcmVzZWFyY2ggcXVlc3Rpb24gY2FuIGJlIHN1bW1hcml6ZWQgYXM6ICJEaXNlbnRhbmdsZSBtZWNoYW5pc21zIG9mIGNlbGx1bGFyIGRpZmZlcmVudGlhdGlvbiBiZXR3ZWVuIHJlZ3VsYXIgc3RlbSBjZWxscyBhbmQgcGx1cmlwb3RlbnQgc3RlbSBjZWxscyBpbiBtaWNlIgotICAgVGhlIGFwcHJvYWNoIHVzZWQgaXMgcHJvdGVvbWljcyBiYXNlZCBvbiBNUyBkYXRhIHRoYXQgd2FzIGdlbmVyYXRlZCBpbiB0d28gZGlmZmVyZW50IGJhdGNoZXMuIFRoZSBkYXRhc2V0cyBhcmUgZ2VuZXJhdGVkIGJ5IGluZHVjaW5nIGRpZmZlcmVudGlhdGlvbiB3aXRoIGhvcnNlLXNlcnVtIG9uIG5vbi1kaWZmZXJlbnRpYXRlZCBtdXNjbGUgbW91c2UgY2VsbHMgKEMyQzEyIGNlbGxzKSBhcyBjb250cm9sIGFuZCBibG9ja2luZyB0aGUgZGlmZmVyZW50aWF0aW9uIGJ5IExJRiBpbiB0cmVhdGVkIHNhbXBsZS4gUHJvdGVvbWUgZGF0YSBzZXQgY29udGFpbnMgdGhyZWUgY29udHJvbCBzYW1wbGVzIGFuZCB0aHJlZSBMSUYgdHJlYXRlZCBzYW1wbGVzIHBlciBpZGVudGlmaWVkIHByb3RlaW4uIFRoZSBQaG9zcGhvIGRhdGEgc2V0IGNvbnRhaW5zIHRoZSBzYW1lIGFtb3VudCBvZiBzYW1wbGVzIGZyb20gYm90aCBncm91cHMsIGJ1dCB0aGVzZSB3ZXJlIGVucmljaGVkIGZvciBwaG9zcGhvcnlsYXRpb24uIFRoaXMgaXMgYSBmb2xsb3cgdXAgZXhwZXJpbWVudCwgc2luY2UgdGhlIGZpcnN0IGV4cGVyaW1lbnQgY29udGFpbmluZyBvbmx5IHRoZSBQcm90ZW9tZSBkYXRhIHNldCBzaG93ZWQgbm8gc2lnbmlmaWNhbnQgaW5jcmVhc2UgZnJvbSBhbnkgcHJvdGVpbiBhbmQgdGhlIG5ldyBoeXBvdGhlc2lzIGlzIGJhc2VkIG9uIHBvc3QtdHJhbnNsYXRpb25hbCBwaG9zcGhvcnlsYXRpb24gYXMgc2lnbmFsLgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMjIERvd25sb2FkIHJhdyBkYXRhIGZyb20gVXBwbWF4CgpgYGB7YmFzaH0KI3JzeW5jIC1yIG5vYWhlQHJhY2toYW0udXBwbWF4LnV1LnNlOi9wcm9qL2cyMDIwMDA0L3ByaXZhdGUvc3R1ZGVudF9wcm9qZWN0cy9waG9zcGhvcHJvdGVvbWljcyAvaG9tZS9ub2FoL3Bob3NwaG9wcm90ZW9taWNzX3Byb2plY3QvCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMjIFNldHRpbmcgd29ya2luZyBkaXJlY3RvcnkgYW5kIGluc3RhbGwgbGlicmFyaWVzCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30Kc2V0d2QoIn4vcGhvc3Bob3Byb3Rlb21pY3NfcHJvamVjdCIpClJlcXVpcmVkUGFja2FnZXMgPC0gYygiQmlvY01hbmFnZXIiLCAiZHBseXIiLCAiaWdyYXBoIiwgInRpZHlyIiwiZ2dwbG90MiIsImdncmVwZWwiKSAKI0luc3RhbGxzIHBhY2thZ2VzIGlmIG5vdCB5ZXQgaW5zdGFsbGVkCmZvciAoaSBpbiBSZXF1aXJlZFBhY2thZ2VzKSB7IAogICAgaWYgKCFyZXF1aXJlKGksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIAogICAgaW5zdGFsbC5wYWNrYWdlcyhpKQp9CkJpb2NNYW5hZ2VyOjppbnN0YWxsKHZlcnNpb24gPSAiMy4xNSIpCmxpYnJhcnkoQmlvY01hbmFnZXIpCkJpb2NNYW5hZ2VyOjppbnN0YWxsKCJTVFJJTkdkYiIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KFNUUklOR2RiKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dyZXBlbCkKcmVtb3ZlKFJlcXVpcmVkUGFja2FnZXMpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMjIExvYWQgcmF3IGRhdGEKCi0gICBDaGFuZ2UgZGVmYXVsdCBzZXBhcmF0b3IgdG8gIjsiCgpgYGB7cn0KcmF3X2RhdGFfcGhvc3BobyA8LSByZWFkLmNzdihmaWxlID0gIn4vcGhvc3Bob3Byb3Rlb21pY3NfcHJvamVjdC9waG9zcGhvcHJvdGVvbWljcy9EYXRhc2V0X1Bob3NwaG8uY3N2Iiwgc2VwID0gIjsiKQpyYXdfZGF0YV9wcm90ZW9tIDwtIHJlYWQuY3N2KGZpbGUgPSAifi9waG9zcGhvcHJvdGVvbWljc19wcm9qZWN0L3Bob3NwaG9wcm90ZW9taWNzL0RhdGFzZXRfUHJvdGVvbWUuY3N2Iiwgc2VwID0gIjsiKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyBJZiBsb29wIHRvIG9taXQgbmEudmFsdWUgZnJvbSBhbGwgQWJ1bmRhbmNlIGNvbHVtbnMKCi0gICBncmVwIGxpbmUgc2VsZWN0cyBhbGwgY29sdW1ucyB0aGF0IGNvbnRhaW4gdGhlIHN0cmluZyAiQWJ1bmRhbmNlIiBhbmQgc2F2ZXMgdGhlIGNvbHVtbiBudW1iZXIgaW4gKkFidW5kYW5jZV9jb2x1bW5zKgotICAgVGhlIGZvciBsb29wIHRoZW4gc2VsZWN0cyBhbGwgcm93IHdlcmUgdGhlcmUgaXMgKm5vKiBOQSB2YWx1ZSBpbiBvbmUgb2YgdGhlIEFidW5kYW5jZSBjb2x1bW5zIGFuZCBjb3BpZXMgdGhlbSB0byBkYXRhX3Bob3NwaG8gdG8gbGVhdmUgdGhlIHJhdyBkYXRhIHVudG91Y2hlZC4KLSAgICoqIShpcy5uYShyYXdfZGF0YV9waG9zcGhvWyxpXSkpKiogZ2l2ZXMgb3V0IGFsbCB0aGUgcm93cyB0aGF0IGRvbid0IGhhdmUgYW4gTkEgdmFsdWUsIHRoZXNlIGdldCBzZWxlY3RlZAoKYGBge3J9CkFidW5kYW5jZV9jb2x1bW5zIDwtIGdyZXAoIkFidW5kYW5jZSIsIGNvbG5hbWVzKHJhd19kYXRhX3Bob3NwaG8pICkKZm9yIChpIGluIEFidW5kYW5jZV9jb2x1bW5zKSB7CiAgZGF0YV9waG9zcGhvIDwtIHJhd19kYXRhX3Bob3NwaG9bIShpcy5uYShyYXdfZGF0YV9waG9zcGhvWyxpXSkpLCBdCiAgfQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyBDYWxjdWxhdGUgTWVhbiBmb3IgQWJ1bmRhbmNlIGFuZCBhZGRpbmcgaXQgYXMgY29sdW1uIGFuZCBSYXRpbyBMSUYvQ29udHJvbAoKLSAgIGdyZXAgYWdhaW4gQWJ1bmRhbmNlIGJ1dCB0aGlzIHRpbWUgdGhlIENvbnRyb2wgYW5kIExJRiAoY2FzZSkgc2VwYXJhdGVseS4KLSAgIGNhbGN1bGF0ZSByb3cgbWVhbnMgZWFjaCBhbmQgdGhlIHJhdGlvbiBiZXR3ZWVuIHRoZSBtZWFucy4KCmBgYHtyfQpBYnVuZGFuY2VfY29sdW1ucyA8LSBncmVwKCJBYnVuZGFuY2UuQ29udHJvbCIsIGNvbG5hbWVzKGRhdGFfcGhvc3BobykpCmRhdGFfcGhvc3BobyRBYnVkYW5jZS5NZWFuLkNvbnRyb2wgPC0gcm93TWVhbnMoZGF0YV9waG9zcGhvWyxjKEFidW5kYW5jZV9jb2x1bW5zKV0pCkFidW5kYW5jZV9jb2x1bW5zIDwtIGdyZXAoIkFidW5kYW5jZS5MSUYiLCBjb2xuYW1lcyhkYXRhX3Bob3NwaG8pKQpkYXRhX3Bob3NwaG8kQWJ1ZGFuY2UuTWVhbi5MSUYgPC0gcm93TWVhbnMoZGF0YV9waG9zcGhvWyxjKEFidW5kYW5jZV9jb2x1bW5zKV0pCmRhdGFfcGhvc3BobyRBYnVkYW5jZS5SYXRpbyA8LSBkYXRhX3Bob3NwaG8kQWJ1ZGFuY2UuTWVhbi5MSUYgLyBkYXRhX3Bob3NwaG8kQWJ1ZGFuY2UuTWVhbi5Db250cm9sCnJlbW92ZShBYnVuZGFuY2VfY29sdW1ucywgaSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyMgQ2FsY3VsYXRlIHAtdmFsdWVzCgotICAgKnQudGVzdCogdG8gY29tcGFyZSBhbGwgMyBDb250cm9sIFw8LVw+IDMgQ2FzZSB2YWx1ZXMuIElmIHRoZXkgYXJlIGRpZmZlcmVudCB0aGVuIHRoZSBwdmFsdWUgXDwgMC4wNSAqKi1cPioqIGluZGljYXRpbmcgYSByZWFsIGRpZmZlcmVuY2VzIGJldHdlZW4gY2FzZSAmIGNvbnRyb2wuIElmIHAtdmFsdWUgaXMgYmlnIHRoZSBkaWZmZXJlbmNlIGlzIGJ5IGNoYW5jZfCfmIQgSSB0cmllZCBpdCBmb3Igcm93IDE4OCB3aGljaCBoYXMgYSBSYXRpb24gbmVhcmx5IGVxdWFsIHRvIDEgKDEuMDIuLi4pIGluZGljYXRpbmcgbm8gZGlmZmVyZW5jZSBpbiBjYXNlIHZzLiBjb250cm9sIGFuZCB0aGUgcCB2YWx1ZSBcfiAwLjcgKHJlYWxseSBiYWQpIGFsc28gaW5kaWNhdGluZyBubyBkaWZmZXJlbmNlLiBUaGUgZm9yIGxvb3AgaXRlcmF0ZXMgaXQgb3ZlciBhbGwgcm93cywgQWxpY2VzIHF1aWNrZXIgYXBwcm9hY2ggdXNlcyB0aGUgYXBwbHkgZnVuY3Rpb24gdGhhdCBhbGxvd3MgcGFyYWxsZWwgaXRlcmF0aW9uIG1ha2luZyBpdCBxdWlja2VyLgoKYGBge3Igd2FybmluZz1GQUxTRX0Kc3RhcnRfZm9yIDwtIFN5cy50aW1lKCkKZm9yIChyb3cgaW4gMTpucm93KGRhdGFfcGhvc3BobykpIHsKICBwX3ZhbHVlIDwtIHQudGVzdChkYXRhX3Bob3NwaG9bcm93LDEwOjEyXSwgZGF0YV9waG9zcGhvW3JvdywxMzoxNV0sIGFsdGVybmF0aXZlID0gImxlc3MiKSAKICAjdGVzdHMgaWYgbWVhbiBvZiBjb250cm9sIGlzIGRpZmZlcmVudCBmcm9tIG1lYW4gb2YgTElGIChjYXNlKSBhbmQgYXNzaWducyBpdCB0byBsaXN0IHBfdmFsdWUKICBkYXRhX3Bob3NwaG8kQWJ1ZGFuY2UucHZhbHVlW3Jvd10gPC0gcF92YWx1ZSRwLnZhbHVlIAogICNzZWxlY3RzIHAudmFsdWUgZnJvbSBsaXN0IGFuZCBhc3NpZ25zIGl0IHRvIG5ldyBjb2x1bW4iQWJ1ZGFuY2UucHZhbHVlIiBpbiB0aGUgY29ycmVjdCByb3cKICB9CmVuZF9mb3IgPC0gU3lzLnRpbWUoKQplbmRfZm9yIC0gc3RhcnRfZm9yICNXZSB3YW50ZWQgdG8gY29tcGFyZSBjYWxjdWxhdGlvbiB0aW1lIHRvIGNvbXBhcmUgdGhlIG1ldGhvZHMKI0FsaWNlIHF1aWNrZXIgYXBwcm9hY2gKZGZfY29weSA8LSBkcGx5cjo6dGliYmxlKGRhdGFfcGhvc3BobykgIyBDb3B5IGRmCnN0YXJ0X2FsaWNlIDwtIFN5cy50aW1lKCkKZGZfY29weVtdIDwtIGxhcHBseShkZl9jb3B5LCBmdW5jdGlvbih4KSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSkpCmRmX2NvcHkkcFZhbHVlcyA8LSBhcHBseShkZl9jb3B5LCAxLCBmdW5jdGlvbih4KSB0LnRlc3QoeFsxMDoxMl0seFsxMzoxNV0sIGFsdGVybmF0aXZlID0gImxlc3MiLCBwYWlyZWQgPSBGKSRwLnZhbHVlKQplbmRfYWxpY2UgPC0gU3lzLnRpbWUoKQplbmRfYWxpY2Utc3RhcnRfYWxpY2UgI1Byb3ZlcyB0aGF0IGFwcGx5IGlzIHg0IGZhc3RlciB0aGVuIGxvb3AKcmVtb3ZlKGVuZF9hbGljZSxlbmRfZm9yLHN0YXJ0X2FsaWNlLHN0YXJ0X2Zvcixyb3cscF92YWx1ZSwgZGZfY29weSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyMgQWRkaW5nIGEgVm9sY2FubyBwbG90IHRvIGV4cGxvcmUgdGhlIGluaXRpYWwgZGF0YQoKLSAgIFRoZSBtYWluIGlkZWEgaXMgdG8gaWRlbnRpZnkgdGhyZXNob2xkcyB0aGF0IGNhbiBiZSB1c2VkIHRvIGNsZWFuIHRoZSByYXcgZGF0YS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIyBQaG9zcGhvIHZvbGNhbm8gcGxvdApzdHJpbmdfZGJfdm9sY2FubyA8LSBTVFJJTkdkYiRuZXcoIHZlcnNpb249IjExLjUiLCBzcGVjaWVzPTEwMDkwLCBzY29yZV90aHJlc2hvbGQ9MSwgaW5wdXRfZGlyZWN0b3J5PSIiKQojIFRoaXMgaGFkIHRvIGJlIG91dHNpZGUgdGhlIHZvbGNhbm9fcGhvc3Bob19wbG90IGZ1bmN0aW9uLCBiZWNhdXNlIHRoZSBmdW5jdGlvbiBkaWRudCByZXR1cm4gdGhlIHN0cmluZ19kYl92b2xjYW5vIGZ1bmN0aW9uIHRoYXQgaXMgbmVlZGVkIGFsc28gYWZ0ZXJ3YXJkcy4KIyBEZWZpbmluZyBmdW5jdGlvbiB0byBwbG90IGRhdGEKICAgICMgTWFrZXMgdGhlIHdob2xlIGNvZGUgZWFzeSB0byByZXVzZS4Kdm9sY2Fub19waG9zcGhvX3Bsb3QgPC0gZnVuY3Rpb24ocGhvc3BobywgbnVtYmVyKXsKIyBDYWxjdWxhdGUgTElGL0NvbnRyb2wgcmF0aW8KcGhvc3BobyRGQyA8LSBwaG9zcGhvJEFidWRhbmNlLk1lYW4uTElGIC8gcGhvc3BobyRBYnVkYW5jZS5NZWFuLkNvbnRyb2wKcGhvc3BobyRsb2cyX0ZDIDwtIGxvZzIocGhvc3BobyRGQykKcGhvc3BobyRkaWZmZXhwcmVzc2VkIDwtICJOTyIKcGhvc3BobyRkaWZmZXhwcmVzc2VkW3Bob3NwaG8kbG9nMl9GQyA+IDEgJiBwaG9zcGhvJEFidWRhbmNlLnB2YWx1ZSA8IDAuMDVdIDwtICJVUCIgIyBzb3J0cyBvdXQgdXByZWd1bGF0ZWQgcGhvc3BvIHZhbHVlcyBhbmQgYXNzaWducyAiVVAiIHZhbHVlLgpwaG9zcGhvJGRpZmZleHByZXNzZWRbcGhvc3BobyRsb2cyX0ZDIDwgLTEgJiBwaG9zcGhvJEFidWRhbmNlLnB2YWx1ZSA8IDAuMDVdIDwtICJET1dOIiAjIHNhbWUgb3IgZG93bnJlZ3VsYXRlZCBwaG9zcGhvIHZhbHVlcwpwaG9zcGhvJGRlbGFiZWwgPC0gTkEKcGhvc3BobyRkZWxhYmVsW3Bob3NwaG8kZGlmZmV4cHJlc3NlZCAhPSAiTk8iXSA8LSBwaG9zcGhvJE1hc3Rlci5Qcm90ZWluLkFjY2Vzc2lvbnNbcGhvc3BobyRkaWZmZXhwcmVzc2VkICE9ICJOTyJdICMgc2VsZWN0aW5nIG9ubHkgdXAgb3IgZG93biByZWd1bGF0ZWQgdmFsdWVzIGFuZCBhc3NpZ25pbmcgdGhlbSB0byB0aGUgbGFiZWwgY29sdW1uLgojI0FkZGl0aW9uIHRvIGdlbmVyYXRlICJyZWFsIG5hbWVzIiBub3QgVW5pcHJvdCBJRHMKTWFwcGluZ19waG9zcGhvIDwtIHN0cmluZ19kYl92b2xjYW5vJG1hcChwaG9zcGhvLCAiZGVsYWJlbCIsIHJlbW92ZVVubWFwcGVkUm93cyA9IEYpCk1hcHBpbmdfcGhvc3BobyA8LSBzdHJpbmdfZGJfdm9sY2FubyRhZGRfcHJvdGVpbnNfZGVzY3JpcHRpb24oTWFwcGluZ19waG9zcGhvKSAjQWRkwrRzIHByb3RlaW4gaW5mb3JtYXRpb24gdG8gU1RSSU5HaWTCtHMgPSBwcmVmZXJyZWQgbmFtZXMgYXJlIG1vcmUgaHVtYW4gcmVhZGFibGUKI1ZvbGNhbm8gcGxvdCBvdmVydmlldwpnZ3Bsb3QoZGF0YT1NYXBwaW5nX3Bob3NwaG8sIGFlcyh4PWxvZzJfRkMsIHk9LWxvZzEwKEFidWRhbmNlLnB2YWx1ZSksIGNvbD1kaWZmZXhwcmVzc2VkLCBsYWJlbD1wcmVmZXJyZWRfbmFtZSkpKwogIGdlb21fcG9pbnQoKSsKICB0aGVtZV9taW5pbWFsKCkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoLTEsIDEpLCBjb2w9InJlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9LWxvZzEwKDAuMDUpLCBjb2w9InJlZCIpCiNzYXZlcyB0aGUgY29ycmVjdCBwaG90byBmb3IgYm90aCBwb3NzaWJsZSBpbnB1dCB0YWJsZXMKIyBudW1iZXIgMSBvciAyIGhhcyB0byBiZSBkZWZpbmVkIGluIHRoZSBmdW5jdGlvbiBpbnB1dCBkYXRhLiBUaGlzIGlzIGEgYml0IGNsdW1zeSBzb2x2ZWQsIGJ1dCB0aGVyZSB3ZXJlIHByb2JsZW1zIHdpdGggcmV0dXJuaW5nIG1vcmUgdGhhbiBvbmUgcGxvdCBvdXQgb2YgYSBmdW5jdGlvbi4KaWYgKG51bWJlciA9PSAxKSB7CiAgZ2dzYXZlKCJ+L3Bob3NwaG9wcm90ZW9taWNzX3Byb2plY3QvcmVzdWx0cy9ab29tZWRfb3V0X1ZvbGNhbm8ucG5nIiwgd2lkdGggPSAxNTAwLCBoZWlnaHQgPSAxMDAwLCB1bml0cyA9ICJweCIpICMgU2F2ZXMgcGxvdHMgd2l0aCBkZWZpbmVkIHNpemUKfQppZiAobnVtYmVyID09IDIpIHsKICBnZ3NhdmUoIn4vcGhvc3Bob3Byb3Rlb21pY3NfcHJvamVjdC9yZXN1bHRzL1pvb21lZF9vdXRfVm9sY2Fub19mb3JfbW9yZV9waG9zcGhyeWxhdGVkX2FmdGVyX3FjX2FuZF9maWx0ZXIucG5nIiwgd2lkdGggPSAxNTAwLCBoZWlnaHQgPSAxMDAwLCB1bml0cyA9ICJweCIpCn0KI0RldGFpbC9ab29tZWQgaW4KZ2dwbG90KGRhdGE9TWFwcGluZ19waG9zcGhvLCBhZXMoeD1sb2cyX0ZDLCB5PS1sb2cxMChBYnVkYW5jZS5wdmFsdWUpLCBjb2w9ZGlmZmV4cHJlc3NlZCwgbGFiZWw9cHJlZmVycmVkX25hbWUpKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfbWluaW1hbCgpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD1jKC0xLCAxKSwgY29sPSJyZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PS1sb2cxMCgwLjA1KSwgY29sPSJyZWQiKSArIAogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygxLDMuNSksIHlsaW0gPSBjKDAuNSwgNikpKwogIGdlb21fbGFiZWxfcmVwZWwoKQojc2F2ZXMgdGhlIGNvcnJlY3QgcGhvdG8gZm9yIGJvdGggcG9zc2libGUgaW5wdXQgdGFibGVzCmlmIChudW1iZXIgPT0gMSkgewogIGdnc2F2ZSgifi9waG9zcGhvcHJvdGVvbWljc19wcm9qZWN0L3Jlc3VsdHMvWm9vbWVkX2luX1ZvbGNhbm8ucG5nIiwgd2lkdGggPSAxNTAwLCBoZWlnaHQgPSAxMDAwLCB1bml0cyA9ICJweCIpCn0KaWYgKG51bWJlciA9PSAyKSB7Cmdnc2F2ZSgifi9waG9zcGhvcHJvdGVvbWljc19wcm9qZWN0L3Jlc3VsdHMvWm9vbWVkX2luX1ZvbGNhbm9fZm9yX21vcmVfcGhvc3BocnlsYXRlZF9hZnRlcl9xY19hbmRfZmlsdGVyLnBuZyIsIHdpZHRoID0gMTUwMCwgaGVpZ2h0ID0gMTAwMCwgdW5pdHMgPSAicHgiKQp9Cn0Kdm9sY2Fub19waG9zcGhvX3Bsb3QoZGF0YV9waG9zcGhvLCAxKSAjcGxvdHMgZGF0YSB0byBjb250cm9sCmBgYAoKIVtPdmVyd2lldiBWb2xjYW5vIFBob3Nob10oaW1hZ2VzL1pvb21lZF9vdXRfVm9sY2Fuby5wbmcpCgohW1pvb21lZCBpbiBWb2xjYW5vIHBsb3QgUGhvc3Bob10oaW1hZ2VzL1pvb21lZF9pbl9Wb2xjYW5vLnBuZykKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyBQcm90ZW9tZSB2b2xjYW5vIHBsb3QKCi0gICBBbHNvIHBsb3R0aW5nIHRoZSBwcm90ZW9tZSBkYXRhIHRvIGlkZW50aWZ5IHRocmVzaG9sZHMgdG8gY2xlYW4gZGF0YQoKYGBge3J9CiMgRGVmaW5pbmcgZnVuY3Rpb24gZmlyc3QKdm9sY2Fub19wbG90X3Byb3Rlb21lIDwtIGZ1bmN0aW9uKHByb3Rlb21lKXsKcHJvdGVvbWUkbG9nMl9GQyA8LSBsb2cyKHByb3Rlb21lJEFidW5kYW5jZS5SYXRpby4uLkxJRi4uLi4uQ29udHJvbC4pCnByb3Rlb21lJGRpZmZleHByZXNzZWQgPC0gIk5PIgpwcm90ZW9tZSRkaWZmZXhwcmVzc2VkW3Byb3Rlb21lJGxvZzJfRkMgPiAxICYgcHJvdGVvbWUkQWJ1bmRhbmNlLlJhdGlvLlAuVmFsdWUuLi5MSUYuLi4uLkNvbnRyb2wuIDwgMC4wNV0gPC0gIlVQIgpwcm90ZW9tZSRkaWZmZXhwcmVzc2VkW3Byb3Rlb21lJGxvZzJfRkMgPCAtMSAmIHByb3Rlb21lJEFidW5kYW5jZS5SYXRpby5QLlZhbHVlLi4uTElGLi4uLi5Db250cm9sLiA8IDAuMDVdIDwtICJET1dOIgpnZ3Bsb3QoZGF0YT1wcm90ZW9tZSwgYWVzKHg9bG9nMl9GQywgeT0tbG9nMTAoQWJ1bmRhbmNlLlJhdGlvLlAuVmFsdWUuLi5MSUYuLi4uLkNvbnRyb2wuKSwgY29sPWRpZmZleHByZXNzZWQpKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfbWluaW1hbCgpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD1jKC0xLCAxKSwgY29sPSJyZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PS1sb2cxMCgwLjA1KSwgY29sPSJyZWQiKQp9CiNQcmludGluZyB0aGUgdm9sY2FubyBwbG90CnZvbGNhbm9fcGxvdF9wcm90ZW9tZShyYXdfZGF0YV9wcm90ZW9tKSAjIFBsb3RzIGFsbCB0aGUgZGF0YSAKYGBgCgotICAgTm8gdmFsdWVzIGFyZSBzaWduaWZpY2FudGx5IHVwIG9yIGRvd24gcmVndWxhdGVkIChkZWZpbmluZyB1cCAvIGRvd24gcmVndWxhdGVkIGFzIGF0IGxlYXN0IDItZm9sZCBpbmNyZWFzZS9kZWNyZWFzZSkuIEFsc28gb3V0bGllcnMgY291bGQgYmUgb2JzZXJ2ZWQgKDQgdmFsZXMgd2l0aCBhIFw+Mi1mb2xkIGluY3JlYXNlIHdpdGggbm9uLXNpZ25pZmljYW50IHAtdmFsdWVzKS4gVG8gYmUgbW9yZSByZXN0cmljdGl2ZSBhbmQgZGVjcmVhc2UgdGhlIGNoYW5nZSBvZiBmYWxzZSBwb3NpdGl2ZXMgaW4gdGhlIHVwY29taW5nIGFuYWx5c2lzLCBhbHNvIHNpZ25pZmljYW50bHkgaW5jcmVhc2VkIHZhbHVlcyB3aXRoIGEgcmF0aW8gXD4gMSB3ZXJlIHNlbGVjdGVkIGFzIHVuZGVzaXJlZCBkYXRhIGFuZCBhcmUgZ29pbmcgdG8gYmUgcmVtb3ZlZCBpbiB0aGUgZm9sbG93aW5nIGNsZWFuaW5nIHN0ZXBzLgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMjIFN1YnNldHRpbmcgZGF0YV9waG9zcGhvIGZvciByYXRpbyB2YWx1ZXMgXD49IDIgYW5kIHAtdmFsdWVzIFw8PSAwLjA1CgotICAgCgogICAgYS4gIFJlbW92ZSBwZXB0aWRlcyB3aXRob3V0IHF1YW50aXRhdGl2ZSB2YWx1ZXMgLVw+IEFscmVhZHkgZG9uZSBpbiAiSWYgbG9vcCB0byBvbWl0IG5hLnZhbHVlIGZyb20gYWxsIEFidW5kYW5jZSBjb2x1bW5zIiB0aGVyZWJ5IGNyZWF0aW5nIHRoZSBkYXRhX3Bob3NwaG8KCi0gICBIZXJlIHdlIHVzZSB0aGUgaWRlbnRpZmllZCB0aHJlc2hvbGRzIGZyb20gdGhlIHZvbGNhbm8gcGxvdHMgdG8gY2xlYW4gdGhlIGRhdGEuIEZpcnN0IHdlIHNlbGVjdCByb3dzIHdpdGggcmF0aW8gXD49IDIgYW5kIHAudmFsdWVzIFw8PSAwLjA1IGZyb20gdGhlIHBob3BobyBkYXRhc2V0LiBGcm9tIHRoZSBwcm90ZW9tIGRhdGEgc2V0IHZhbHVlcyB3ZXJlIHNlbGVjdGVkIHdpdGggYSBhbGwgcm93cyB3aXRoIGEgcmF0aW8gXDw9IDEsIGFsbCByb3dzIHdpdGggYSByYXRpbyBcPj0gMSBhbmQgcC52YWx1ZSBcPD0gMC4wNSAoZWxldmF0ZWQgcHJvdGVpbnMgKHJhdGlvIFw+PTEpIHdpdGggc2lnbmlmaWNhbnQgcC12YWx1ZXMgYXJlIGV4Y2x1ZGVkIGFuZCBwcm90ZWluIHdpdGggcmF0aW9zIGJpZ2dlciB0aGFuIDIgKGRpc3JlZ2FyZGluZyBwLXZhbHVlKSwgdG9vKS4gQWZ0ZXIgdGhpcyBpbml0aWFsIGNsZWFudXAgYSBzZW1pX2pvaW4oKSB3YXMgcGVyZm9ybWVkIHJldHVybmluZyBhbGwgcm93cyBmcm9tIGNsZWFudXAgcGhvc3BobyB3aXRoIGEgbWF0Y2ggaW4gY2xlYW51cCBwcm90ZW9tZSwgdG8gc2VsZWN0IG9ubHkgcGhvc3BvIHZhbHVlcyB0aGF0IHNob3dlZCBpbmNyZWFzZWQgcGhvc3Bob3J5bGF0aW9uIGR1ZSB0byB0aGUgTElGIHRyZWF0bWVudCBhbmQgbm90IGR1ZSB0byBlbGV2YXRlZCBleHByZXNzaW9uIGxldmVscy4KCi0gICB2b2xjYW5vIHBsb3RzIHdlcmUgdXNlZCB0byB2aXN1YWxpemUgdGhlIGNsZWFuaW5nL3NlbGVjdGluZyBzdGVwcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyNGaWx0ZXIgTkEgb3V0IGluIHByb3Rlb21lLCBGaWx0ZXIgb3V0IHAudmFsdWVzIHRoYXQgYXJlIG5vbiBzaWduaWZpY2FudChub3QgYWRqdXN0ZWQpCiAgI3NlY3VyaW5nIG5vIG92ZXJ3cml0ZSB0byBvcmlnaW5hbCBkYXRhCmRmX3Bob3NwaG8gPSBkYXRhX3Bob3NwaG8KZGZfcHJvdGVvbWUgPSByYXdfZGF0YV9wcm90ZW9tCiAgCiMjIEZpbHRlciBQSE9TUEhPCiAgbW9yZV9waG9zcGhvIDwtIHN1YnNldC5kYXRhLmZyYW1lKGRmX3Bob3NwaG8sIHN1YnNldCA9IGRmX3Bob3NwaG8kQWJ1ZGFuY2UuUmF0aW8gPj0gMikgI0ZpbHRlcnMgb3V0IGFsbCByYXRpb3MgYmVsb3cgMi1mb2xkCiAgbW9yZV9waG9zcGhvIDwtIHN1YnNldC5kYXRhLmZyYW1lKG1vcmVfcGhvc3Bobywgc3Vic2V0ID0gbW9yZV9waG9zcGhvJEFidWRhbmNlLnB2YWx1ZSA8PSAwLjA1KSAjRmlsdGVycyBvdXQgYWxsIG5vbi1zaWduaWZpY2FudCBwLXZhbHVlcwogIAogICMjRmlsdGVyIFBST1RFT01FCiAgZXhjbHVkZV9wcm90ZW9tZSA8LSBmaWx0ZXIoZGZfcHJvdGVvbWUsIGRmX3Byb3Rlb21lJEFidW5kYW5jZS5SYXRpby5QLlZhbHVlLi4uTElGLi4uLi5Db250cm9sLiA8PSAwLjA1ICYgZGZfcHJvdGVvbWUkQWJ1bmRhbmNlLlJhdGlvLi4uTElGLi4uLi5Db250cm9sLiA+PSAxKSAjRmlsdGVycyBvdXQgYWxsIHNpZ25pZmljYW50IHAtdmFsdWVzLCBiZWNhdXNlIHNpZ25pZmljYW50IHAtdmFsdWVzIGluZGljYXRlIGFuIAogICNEYXRhIHRoYXQgd2Ugd2FudCB0byBleGNsdWRlLCB0ZXN0aW5nIGlmIHRoZSByaWdodCBkYXRhIGlzIHNlbGVjdGVkIHdpdGggdGhlIHZvbGNhbm8gcGxvdAogIHZvbGNhbm9fcGxvdF9wcm90ZW9tZShleGNsdWRlX3Byb3Rlb21lKQogICNBbnRpX2pvaW4gYW50aV9qb2luKCkgcmV0dXJuIGFsbCByb3dzIGZyb20geCB3aXRob3V0IGEgbWF0Y2ggaW4geS4gCiAgbW9yZV9wcm90ZW9tZSA8LSBhbnRpX2pvaW4oZGZfcHJvdGVvbWUsIGV4Y2x1ZGVfcHJvdGVvbWUsIGJ5ID0gYygiQWNjZXNzaW9uIiA9ICJBY2Nlc3Npb24iKSkKICBtb3JlX3Byb3Rlb21lIDwtIGZpbHRlcihtb3JlX3Byb3Rlb21lLCBtb3JlX3Byb3Rlb21lJEFidW5kYW5jZS5SYXRpby4uLkxJRi4uLi4uQ29udHJvbC4gPD0gMikgIyByZW1vdmVzIG91dGxpZXJzIHdpdGggcmF0aW8gYmlnZ2VyIHRoZW4gMgogICNDaGVja2luZyB0aGUgaWYgdGhlIHJpZ2h0IGRhdGEgaXMgZXhjbHVkZWQKICB2b2xjYW5vX3Bsb3RfcHJvdGVvbWUobW9yZV9wcm90ZW9tZSkKICAKICAjSW5uZXIgam9pbiB3b3JrcyB0b28sIGJ1dCBzZW1pIGpvaW4gaXMgYmV0dGVyIGJlY2FzdWUgdGhlIHByb3Rlb21lIGNvbHVtbnMgYXJlIG5vdCBpbmNsdWRlZCBpbnRvIHRoZSByZXN1bHRpbmcgZGF0YSBmcmFtZS4KICAjbW9yZV9waG9zcGhvcnlsYXRlZCA8LSBkcGx5cjo6aW5uZXJfam9pbiggbW9yZV9waG9zcGhvLCBtb3JlX3Byb3Rlb21lLCBieSA9IGMoIk1hc3Rlci5Qcm90ZWluLkFjY2Vzc2lvbnMiID0gIkFjY2Vzc2lvbiIpKQogIAogICNTZW1pLWpvaW4gI3NlbWlfam9pbigpIHJldHVybiBhbGwgcm93cyBmcm9tIHggd2l0aCBhIG1hdGNoIGluIHkuIAogIG1vcmVfcGhvc3Bob3J5bGF0ZWQgPC0gZHBseXI6OnNlbWlfam9pbihtb3JlX3Bob3NwaG8sIG1vcmVfcHJvdGVvbWUsIGJ5ID0gYygiTWFzdGVyLlByb3RlaW4uQWNjZXNzaW9ucyIgPSAiQWNjZXNzaW9uIikpCiAgdm9sY2Fub19waG9zcGhvX3Bsb3QobW9yZV9waG9zcGhvcnlsYXRlZCwgMikgIyB0byBjb250cm9sIHJlbWFpbmluZyBkYXRhCiAgCnJlbW92ZShkZl9waG9zcGhvLCBkZl9wcm90ZW9tZSwgbW9yZV9waG9zcGhvLCBtb3JlX3Byb3Rlb21lLCBleGNsdWRlX3Byb3Rlb21lKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyBDb21wYXJpbmcgZGF0YSBiZWZvcmUgYW5kIGFmdGVyIHRoZSBjbGVhbnVwCgotd2UgY291bGQgaWRlbnRpZnkgdGhhdCB0aGUgY2xlYW51cCB3YXMgY29uZHVjdGVkIGFuZCBub3QgdG9vIHN0cmluZ2VudCByZXR1cm5pbmcgZW5vdWdoIGRhdGEgdG8gY29uZHVjdCBhbmFseWlzaXMgb24uCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyMgIVtWb2xjYW5vIG9mIGRhdGFfcGhvc3BobyBiZWZvcmUgZmlsdGVyXShpbWFnZXMvWm9vbWVkX2luX1ZvbGNhbm8tMDEucG5nKXt3aWR0aD0iMzUwIn0hW1pvb21lZCBpbiBWb2xjYW5vIGZyb20gbW9yZSBwaG9zcGhvcnlsYXRlZCBhZnRlciBmaWx0ZXJdKGltYWdlcy9ab29tZWRfaW5fVm9sY2Fub19mb3JfbW9yZV9waG9zcGhyeWxhdGVkX2FmdGVyX3FjX2FuZF9maWx0ZXIucG5nKXt3aWR0aD0iMzUwIn0KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyAKCiMjIyMgQnVpbGRpbmcgbmV0d29yayBtYXAgb2YgdGhlIHByb3RlaW5zCgotICAgV2l0aCBoZWxwIG9mIHRoZSBTVFJJTmdkYiBwYWNrYWdlIHRoZSBvdmVydmlldyBuZXR3b3JrcyB3ZXJlIHByb2R1Y2VkIHdpdGggZGlmZmVyZW50IHRocmVzaG9sZHMuCgpgYGB7cn0KIyNMb3dlciBzY29yZV90aHJlc2hvbGQsIGFsbG93aW5nIG1vcmUgY29ubmVjdGlvbnMKc3RyaW5nX2RiX2xvdyA8LSBTVFJJTkdkYiRuZXcodmVyc2lvbj0iMTEuNSIsIHNwZWNpZXM9MTAwOTAsIHNjb3JlX3RocmVzaG9sZD0xLCBpbnB1dF9kaXJlY3Rvcnk9IiIpICNzcGVjaWVzID0gbW91c2UgaWRlbnRpZmllciwgc2NvcmUgdGhyZXNob2xkID0gaWYgb25lIGludGVyYWN0aW9uIHRoaXMgd2lsbCBiZSBtYXBwZWQsIG5vIGlucHV0IGRpcmVjdG9yeSBkYXRhIHN0b3JlZCBvbmx5IHRlbXBvcmFyeQpoaXRzX2xvdyA8LSBzdHJpbmdfZGJfbG93JG1hcChtb3JlX3Bob3NwaG9yeWxhdGVkLCAiTWFzdGVyLlByb3RlaW4uQWNjZXNzaW9ucyIsIHJlbW92ZVVubWFwcGVkUm93cyA9IEYpICNtYXBwaW5nIHRoZSBVTklQUk9UIElkcyBmcm9tIHRoZSBmaXJzdCBjb2x1bW4gdG8gZ2V0IFNUUklORyBpZGVudGlmaWVycwpzdHJpbmdfZGJfbG93JHBsb3RfbmV0d29yayhoaXRzX2xvdyRTVFJJTkdfaWQpICNwbG90dGluZyBuZXR3b3JrCmludmlzaWJsZShzdHJpbmdfZGJfbG93JGdldF9wbmcoaGl0c19sb3ckU1RSSU5HX2lkLCBmaWxlID0gIn4vcGhvc3Bob3Byb3Rlb21pY3NfcHJvamVjdC9yZXN1bHRzL05ldHdvcmtfbG93LnBuZyIpKSAjU2F2aW5nIHBob3RvCiMjIEhpZ2hlciBzY29yZV90aHJlc2hvbGQsIGFsbG93aW5nIGxlc3MgY29ubmVjdGlvbnMKc3RyaW5nX2RiX2hpZ2ggPC0gU1RSSU5HZGIkbmV3KHZlcnNpb249IjExLjUiLCBzcGVjaWVzPTEwMDkwLCBzY29yZV90aHJlc2hvbGQ9MjAwLCBpbnB1dF9kaXJlY3Rvcnk9IiIpICNzcGVjaWVzID0gbW91c2UgaWRlbnRpZmllciwgc2NvcmUgdGhyZXNob2xkID0gaWYgb25lIGludGVyYWN0aW9uIHRoaXMgd2lsbCBiZSBtYXBwZWQsIG5vIGlucHV0IGRpcmVjdG9yeSBkYXRhIHN0b3JlZCBvbmx5IHRlbXBvcmFyeQpoaXRzX2hpZ2ggPC0gc3RyaW5nX2RiX2hpZ2gkbWFwKG1vcmVfcGhvc3Bob3J5bGF0ZWQsICJNYXN0ZXIuUHJvdGVpbi5BY2Nlc3Npb25zIiwgcmVtb3ZlVW5tYXBwZWRSb3dzID0gRikgI21hcHBpbmcgdGhlIFVOSVBST1QgSWRzIGZyb20gdGhlIGZpcnN0IGNvbHVtbiB0byBnZXQgU1RSSU5HIGlkZW50aWZpZXJzCnN0cmluZ19kYl9oaWdoJHBsb3RfbmV0d29yayhoaXRzX2hpZ2gkU1RSSU5HX2lkKSAjcGxvdHRpbmcgbmV0d29yawppbnZpc2libGUoc3RyaW5nX2RiX2hpZ2gkZ2V0X3BuZyhoaXRzX2hpZ2gkU1RSSU5HX2lkLCBmaWxlID0gIn4vcGhvc3Bob3Byb3Rlb21pY3NfcHJvamVjdC9yZXN1bHRzL05ldHdvcmtfaGlnaC5wbmciKSkgI1NhdmluZyBwaG90bwpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyBXYXkgdG8gaWRlbnRpZnkgdGhlIFByb3RlaW5zIFN0YXQ1YiBpcyBjb25uZWN0ZWQgdG8uCgotICAgSW4gdGhpcyBjaHVuayB3ZSBkZWZpbmUgYSBmdW5jdGlvbiB3aXRoIGEgbW9yZSBhbmQgYSBsZXNzIHN0cmluZ2VudCB0aHJlc2hvbGQgdG8gZ2V0IDEuIFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIgZm9yIG1vcmUgb3IgbGVzcyBzdHJpbmdlbnQgdGhyZXNob2xkLCAyLiBOZXR3b3JrIHBsb3QgZm9yIHRoZSBzdWJuZXR3b3JrcyBvZiBwcm90ZWlucyBjb25uZWN0ZWQgdG8gU3RhdDViLCAzLiBMaW5rIHRvIHdlYnBhZ2UgZm9yIHRoZSBzdWJuZXR3b3JrcywgNC4gUGF0aHdheXMgdGhhdCBhcmUgZW5yaWNoZWQgaW4gdGhlIHN1Ym5ldHdvcmtzLgoKLSAgIFRoZXJlIGlzIGFsc28gYSBsaW5rIHRvIHRoZSBbU1RSSU5HZGIgd2Vic2l0ZSBmb3IgbGVzcyBzdHJpbmdlbnQgdGhyZXNob2xkID0gMV0oaHR0cHM6Ly92ZXJzaW9uLTExLTUuc3RyaW5nLWRiLm9yZy9jZ2kvbGluaz90bz0yRThDREM5OTBEQkQxMEY3KSB3aXRoIHRoZSBQcm90ZWlucyBjb25uZWN0ZWQgdG8gU3RhdDViIGluIHRoaXMgZGF0YXNldC4KCi0gICBUaGVyZSBpcyBhbHNvIGEgbGluayB0byB0aGUgW1NUUklOR2RiIHdlYnNpdGUgZm9yIG1vcmUgc3RyaW5nZW50IHRocmVzaG9sZCA9IDIwMF0oaHR0cHM6Ly92ZXJzaW9uLTExLTUuc3RyaW5nLWRiLm9yZy9jZ2kvbGluaz90bz0xOEI1QzNFMTZFOUIzQUUwKSB3aXRoIHRoZSBQcm90ZWlucyBjb25uZWN0ZWQgdG8gU3RhdDViIGluIHRoaXMgZGF0YXNldC4KCmBgYHtyfQojRmluZGluZyBTdHJpbmcgaWQgaWRlbnRpZmllciBmb3IgU3RhdDViIGFuZCBhc3NpZ25pbmcgaXQgdG8gdGhlIGEgdmFyaWFibGUKaSA8LSBncmVwKCJQNDIyMzIiLCBoaXRzX2xvdyRNYXN0ZXIuUHJvdGVpbi5BY2Nlc3Npb25zKSAKU3RhdDViIDwtIHN0cmluZ19kYl9sb3ckbXAoIlA0MjIzMiIpICNtYXBwaW5nIHRoZSBVTklQUk9UIElkcyAKIyMgTWFwcGluZyBTdGF0NWIgaW50ZXJhY3Rpb25zIGluIHRoZSBsZXNzIHN0cmluZ2VudCBkYXRhIHNldCBhbmQgbW9yZSBzdHJpbmdlbnQgZGF0YSBzZXQKI0RlZmluaW5nIGEgZnVuY3Rpb24gdG8gZ2V0IDEuIFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIsIDIuIE5ldHdvcmsgcGxvdCwgMy4gTGluayB0byB3ZWJwYWdlLCA0LiBQYXRod2F5cwpzdWJuZXR3b3JrcyA8LSBmdW5jdGlvbihkYXRhX2gsc2NvcmVfaCkgewogICNhID0gVGhlIGRhdGEgd2Ugd2FudCB0byBoYXZlIGEgbmV0d29yayBmcm9tLCBiID0gdGhlIHRocmVzaG9sZCBudW1iZXIgb2YgdGhlIHN0cmluZ19kYiBmdW5jdGlvbgogIHN0cmluZ19kYiA8LSBTVFJJTkdkYiRuZXcodmVyc2lvbj0iMTEuNSIsIHNwZWNpZXM9MTAwOTAsIHNjb3JlX3RocmVzaG9sZCA9IHNjb3JlX2gsIGlucHV0X2RpcmVjdG9yeT0iIikgI3NwZWNpZXMgPSBtb3VzZSAKICBnZXQgPC0gc3RyaW5nX2RiJGdldF9zdWJuZXR3b3JrKGRhdGFfaCkgI2J1aWxkcyBzdWJuZXR3b3JrIGZyb20gZXZlcnkgZW50cnkgaW4gU1RSSU5HX2lkCiAgZ2hpIDwtIGdldFtbU3RhdDViXV1bMV0gIyNnaXZlcyB0aGUgbGlzdCBlbnRyeSBvZiAiZ2V0IiB0aGF0IGxpc3RzIGFsbCAxOCBlbnRyaWVzIHRoYXQgaW50ZXJhY3Qgd2l0aCBTdGF0NWIKICBoZyA8LSB1bmlxdWUoZ2hpJGAxMDA5MC5FTlNNVVNQMDAwMDAxMDI5ODFgKSAjZ2l2ZXMgdGhlIHVuaXF1ZSBpbnRlcmFjdGlvbiAoOSBvdXQgb2YgMTgpLCAKICBtYXQgPC0gYXNfaWRzKGdoaSRgMTAwOTAuRU5TTVVTUDAwMDAwMTAyOTgxYCkgI2Z1bmN0aW9uIGFzX2lkcyBmcm9tIHRoZSBpZ3JhcGggcGFja2FnZSByZWFkcyB0aGUgY2xhc3MoImlncmFwaC52cyIpICAgYW5kIGNvbGxhcHNlcyBpdCBpbnRvIGEgbWF0cml4CiAgUHJvdGVpbnNfY29ubmVjdGVkX3RvX1N0YXQ1YiA8LSBhcy5kYXRhLmZyYW1lKHVuaXF1ZShtYXQpKQogIG5hbWVzKFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIpWzFdIDwtICJTVFJJTkdfaWQiICNSZW5hbWluZyBjb2x1bW4gc28gdGhhdCBhZGRfcHJvdGVpbl9kZXNjcmlwdGlvbiByZWNvZ25pemVzIGl0CiAgUHJvdGVpbnNfY29ubmVjdGVkX3RvX1N0YXQ1YlsobnJvdyhQcm90ZWluc19jb25uZWN0ZWRfdG9fU3RhdDViKSsxKSxdIDwtIFN0YXQ1YiAjQWRkcyBTdGF0NWIgdG8gbWFwIGl0cyBjb25uZWN0aW9ucwogIFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIgPC0gc3RyaW5nX2RiJGFkZF9wcm90ZWluc19kZXNjcmlwdGlvbihQcm90ZWluc19jb25uZWN0ZWRfdG9fU3RhdDViKSAjQWRkwrRzIHByb3RlaW4gaW5mb3JtYXRpb24gdG8gU1RSSU5HaWTCtHMKICAKICAjUGxvdHRpbmcgdGhlIHN1Ym5ldHdvcmsKICBzdHJpbmdfZGIkcGxvdF9uZXR3b3JrKFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIkU1RSSU5HX2lkKQogIAogICNwcm92aWRpbmcgbXkgbGluawogIGxpbmsgPC0gc3RyaW5nX2RiJGdldF9saW5rKFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIkU1RSSU5HX2lkKSAjUHJvdmlkZXMgbGluayB0byB0aGUgU1RSSU5HZGIgcGFnZQogIAogICNQcm92aWRpbmcgdGhlIHBhdGh3YXlzCiAgcGF0aHdheXMgPC0gc3RyaW5nX2RiJGdldF9lbnJpY2htZW50KFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIsIGNhdGVnb3J5ID0gIktFR0ciKQogIHJldHVybihsaXN0KFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWIsIHBhdGh3YXlzLCBsaW5rKSkKICAKICByZW1vdmUoZ2V0LGdoaSxoZyxtYXQpCiAgIH0KIyMgTGVzcyBzdHJpbmdlbnQgcGFyYW1ldGVyIHRvIGRldGVybWluZSB0aGUgUHJvdGVpbnMgdGhhdCBpbnRlcmFjdCB3aXRoIFN0YXQ1CnN1Ym5ldHdvcmtfbGVzc19zdHJpbmdlbnQgPC0gc3VibmV0d29ya3MoZGF0YV9oID0gaGl0c19sb3ckU1RSSU5HX2lkLCBzY29yZV9oID0gMSkgI1VzaW5nIGZ1bmN0aW9uCiNTdWItc2V0dGluZyB0aGUgcmV0dXJuZWQgbGlzdCBpbnRvIG9yaWdpbmFsIGRhdGFmcmFtZXMgKyBsaW5rClByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWJfbGVzcyA8LSBzdWJuZXR3b3JrX2xlc3Nfc3RyaW5nZW50W1sxXV0KcGF0aHdheXNfbGVzcyA8LSBzdWJuZXR3b3JrX2xlc3Nfc3RyaW5nZW50W1syXV0KTGlua19sZXNzIDwtIHN1Ym5ldHdvcmtfbGVzc19zdHJpbmdlbnRbWzNdXQpMaW5rX2xlc3MgI0xpbmsgdG8gd2Vic2l0ZQppbnZpc2libGUoc3RyaW5nX2RiX2xvdyRnZXRfcG5nKFByb3RlaW5zX2Nvbm5lY3RlZF90b19TdGF0NWJfbGVzcyRTVFJJTkdfaWQsIGZpbGUgPSAifi9waG9zcGhvcHJvdGVvbWljc19wcm9qZWN0L3Jlc3VsdHMvTmV0d29ya19TdGF0NV9sZXNzLnBuZyIpKSAjU2F2aW5nIHBuZwojIyBNb3JlIHN0cmluZ2VudCBwYXJhbWV0ZXIgdG8gZGV0ZXJtaW5lIHRoZSBQcm90ZWlucyB0aGF0IGludGVyYWN0IHdpdGggU3RhdDUKc3VibmV0d29ya19tb3JlX3N0cmluZ2VudCA8LSBzdWJuZXR3b3JrcyhkYXRhX2ggPSBoaXRzX2hpZ2gkU1RSSU5HX2lkLCBzY29yZV9oID0gMjAwKSAjVXNpbmcgZnVuY3Rpb24KI1N1Yi1zZXR0aW5nIHRoZSByZXR1cm5lZCBsaXN0IGludG8gb3JpZ2luYWwgZGF0YWZyYW1lcyArIGxpbmsKUHJvdGVpbnNfY29ubmVjdGVkX3RvX1N0YXQ1Yl9tb3JlIDwtIHN1Ym5ldHdvcmtfbW9yZV9zdHJpbmdlbnRbWzFdXSAKcGF0aHdheXNfbW9yZSA8LSBzdWJuZXR3b3JrX21vcmVfc3RyaW5nZW50W1syXV0KTGlua19tb3JlIDwtIHN1Ym5ldHdvcmtfbW9yZV9zdHJpbmdlbnRbWzNdXQpMaW5rX21vcmUgI0xpbmsgdG8gd2Vic2l0ZSAKaW52aXNpYmxlKHN0cmluZ19kYl9oaWdoJGdldF9wbmcoUHJvdGVpbnNfY29ubmVjdGVkX3RvX1N0YXQ1Yl9tb3JlJFNUUklOR19pZCwgZmlsZSA9ICJ+L3Bob3NwaG9wcm90ZW9taWNzX3Byb2plY3QvcmVzdWx0cy9OZXR3b3JrX1N0YXQ1X21vcmUucG5nIikpICNTYXZpbmcgcG5nCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMjIFByaW50aW5nIFBhdGh3YXlzCgotcHJpbnRpbmcgdGhlIGVucmljaGVkIHBhdGh3YXlzIGZyb20gdGhlIHN1Ym5ldHdvcmtzIG9mIFN0YXQ1YiBhbmQgcmVuYW1pbmcgdGhlbSBmb3IgYSBiZXR0ZXIgaHVtYW4gcmVhZGFiaWxpdHkgJiBmb3JtYXR0aW5nIG9mIGh0bWwgZG9jdW1lbnQuCgpgYGB7ciBwYWdlZC5wcmludD1UUlVFfQojSWRlbnRpZnlpbmcgb25seSBmb3IgUHJvdGVpbnMgY29ubmVjdGVkIHRvIFN0YXQ1YgojRnVuY3Rpb24gdG8gZ2VuZXJhdGUgdGFiZWxzIGJhc2VkIG9uIGZhY3RvciBnZW5lIGNvdW50cyAvIG51bWJlciBvZiBhbm5vdGF0ZWQgZ2VuZXMuCmZhY3Rvcl9mdW5jdGlvbiA8LSBmdW5jdGlvbihQYXRod2F5KXsKaSA9IDEKZm9yIChpIGluIGk6bnJvdyhQYXRod2F5KSkgewogIFBhdGh3YXkkZmFjdG9yW2ldIDwtIHJvdW5kKChQYXRod2F5W2ksM10vUGF0aHdheVtpLDRdKSwgZGlnaXRzID0gMykgI3JvdW5kZWQgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uCn0KUGF0aHdheSA8LSByZW5hbWUoUGF0aHdheSwgYmFja2dyb3VuZCA9IG51bWJlcl9vZl9nZW5lc19pbl9iYWNrZ3JvdW5kKQpQYXRod2F5IDwtIHJlbmFtZShQYXRod2F5LCBoaXRzID0gbnVtYmVyX29mX2dlbmVzKQpQYXRod2F5IDwtIHJlbmFtZShQYXRod2F5LCBpbnZvbHZlZF9nZW5lcyA9IHByZWZlcnJlZE5hbWVzKQpQYXRod2F5IDwtIFBhdGh3YXlbb3JkZXIoUGF0aHdheSRmYWN0b3IsZGVjcmVhc2luZyA9IFQgKSxdCnJldHVybihwcmludC5kYXRhLmZyYW1lKFBhdGh3YXlbMTo1LGMoMTEsMyw0LDEwLDcpXSwgcm93Lm5hbWVzID0gRikpCn0KI1RhYmxlIGZvciBsZXNzIHN0cmluZ2VudCBwYXJhbWV0ZXJzCmZhY3Rvcl9mdW5jdGlvbihwYXRod2F5c19sZXNzKQojVGFibGUgZm9yIG1vcmUgc3RyaW5nZW50IHBhcmFtZXRlcnMKZmFjdG9yX2Z1bmN0aW9uKHBhdGh3YXlzX21vcmUpCiMjIFRoaXMgcGFydCBkb2VzIG5vdCB3b3JrIHdpdGggU1RSSU5HZGIgdmVyc2lvbiAxMS41LCBpdCB3b3JrZWQgcHJvcGVybHkgd2l0aCB2ZXJzaW9uIDExLjBiCiNJZGVudGlmeWluZyBwYXRod2F5cyBhbHNvIGZvciBQcm90ZWlucyB3aXRoIGEgcmF0aW8gPj0yIGFuZCBwLnZhbHVlIDw9IDAuMDUgYW5kIHRocmVzaG9sZCA9IDIwMC4KI0JpZ19uZXR3b3JrX3BhdGh3YXlzX21vcmUgPC0gc3RyaW5nX2RiX2hpZ2gkZ2V0X2VucmljaG1lbnQoaGl0c19oaWdoJFNUUklOR19pZCwgY2F0ZWdvcnkgPSAiS0VHRyIpCiNmYWN0b3JfZnVuY3Rpb24oQmlnX25ldHdvcmtfcGF0aHdheXNfbW9yZSkKI0lkZW50aWZ5aW5nIHBhdGh3YXlzIGFsc28gZm9yIFByb3RlaW5zIHdpdGggYSByYXRpbyA+PTIgYW5kIHAudmFsdWUgPD0gMC4wNSBhbmQgdGhyZXNob2xkID0gMS4KI0JpZ19uZXR3b3JrX3BhdGh3YXlzX2xlc3MgPC0gc3RyaW5nX2RiX2xvdyRnZXRfZW5yaWNobWVudChoaXRzX2xvdyRTVFJJTkdfaWQsIGNhdGVnb3J5ID0gIktFR0ciKQojZmFjdG9yX2Z1bmN0aW9uKEJpZ19uZXR3b3JrX3BhdGh3YXlzX2xlc3MpCnJlbW92ZShpLCBMaW5rX2xlc3MsIExpbmtfbW9yZSwgc3RyaW5nX2RiX2hpZ2gsIHN0cmluZ19kYl9sb3csIHN1Ym5ldHdvcmtzLCB2b2xjYW5vX3Bsb3RfcHJvdGVvbWUsIHN1Ym5ldHdvcmtfbGVzc19zdHJpbmdlbnQsIHN1Ym5ldHdvcmtfbW9yZV9zdHJpbmdlbnQsIGhpdHNfaGlnaCwgaGl0c19sb3csIGRhdGFfcGhvc3BobywgZmFjdG9yX2Z1bmN0aW9uLCB2b2xjYW5vX3Bob3NwaG9fcGxvdCwgc3RyaW5nX2RiX3ZvbGNhbm8pCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMjIFJlc3VsdHMgYW5kIERpc2N1c3Npb24KCi0gICBTdGF0NWIgd2FzIHBpY2tlZCBhcyB0aGUgbGVhZCB0YXJnZXQgc2luY2UgaXQgc2hvd2VkIHRoZSBoaWdoZXN0IHNpZ25pZmljYW50IHJhdGlvIGFmdGVyIGRhdGEgY2xlYW4gdXAgaW4gdGhlIHBob3NwaG8gZGF0YSBzZXQuCgotICAgVGhlIG1vcmUgc3RyaW5nZW50IHBhcmFtZXRlcnMgdHVybmVkIG91dCBsZXNzIHByb3RlaW5zIGNvbm5lY3RlZCB0byBTdGF0NWIvNWEgYnV0IHdpdGggYSBoaWdoZXIgc2VjdXJpdHkgb2YgdHJ1ZSBhc3NvY2lhdGlvbi4gVGhlIGdlbmVyYXRlZCBzdWJuZXR3b3JrIGZvciBTdGF0NWIgc2hvd2VkIGEgdmVyeSBwcm9taXNpbmcgdGFyZ2V0IGZvciBmdXJ0aGVyIGludmVzdGlnYXRpb24sIHNpbmNlIGEgbmV0d29yayBldm9sdmVkIGFyb3VuZCBTdGF0NWIuIEdlbmVyYXRlZCBwYXRod2F5cyB0byBpbnZlc3RpZ2F0ZSB0aGUgZWZmZWN0IG9mIGluY3JlYXNlZCBwaG9zcGhvcnlsYXRpb24gcmV0dXJuZWQgbWFueSBjYW5jZXItcmVsYXRlZCBwYXRod2F5cyBpbmRpY2F0aW5nIGEgY29ubmVjdGlvbiBiZXR3ZWVuIHJldGFpbmluZyBhIG5vbi1kaWZmZXJlbnRpYXRlZCBzdGF0ZSBpbiBzdGVtIGNlbGxzIGFuZCB0aGUgY2FwYWJpbGl0eSBvZiBjYW5jZXJvdXMgY2VsbHMgdG8gZm9ybSBjYW5jZXJvdXMgbWFzc2VzLiBPZiB0aGUgbm9uLWNhbmNlciBwYXRod2F5cyBKQUstU1RBVCBpcyBvZiBtb3N0IGltcG9ydGFuY2Ugc2luY2UgaXQncyBhbHNvIHRoZSBzdWIgcGF0aHdheSBhZmZlY3RlZCBpbiB0aGUgY2FuY2VyIHBhdGh3YXlzLgoKICAgICFbSkFLLVNUQVQtcGF0aHdheSB3aXRoIFN0YXQ1YS81YiwgU29zMSBhbmQgUHRwbjExIChTSFAyKSBpbiBwaW5rIGZyb20gS0VHRywgZW50cnkgW21tdTA0NjMwXShodHRwczovL3d3dy5rZWdnLmpwL2tlZ2ctYmluL3Nob3dfcGF0aHdheT9tbXUwNDYzMCkuXShpbWFnZXMvamFrLXN0YXRfcGF0aHdheS5wbmcpCgotICAgVGhlIGxlc3Mgc3RyaW5nZW50IHBhcmFtZXRlcnMgdHVybmVkIG91dCBtb3JlIHByb3RlaW5zIGNvbm5lY3RlZCB0byBTdGF0NWIvNWEgYnV0IGhhcyBhIGhpZ2hlciByaXNrIG9mIGZhbHNlIHBvc2l0aXZlIGNvbm5lY3Rpb25zLiBUaGUgbW9zdCBpbXBvcnRhbnQgaW52b2x2ZWQgZ2VuZXMgd2VyZSBTdGF0NWEvYi4gU3RhdDViIGZvcm1zIGhvbW8tIGFuZCBoZXRlcm8gZGltZXJzIHdpdGggdGhlIHBhcmFsb2cgU3RhdDVhLiBVcG9uIFR5ci1waG9zcGhvcnlsYXRpb24gdGhleSBkaW1lcml6ZSBhbmQgdHJhbnNsb2NhdGlvbiBpbnRvIHRoZSBudWNsZXVzIHRha2VzIHBsYWNlLCB3aGVyZSBpdCBhY3RzIGFzIFt0cmFuc2NyaXB0aW9uIGZhY3Rvcl0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwNzQvamJjLjI3NC4zMi4yMjQ4NCkuIFRoZSBtb3JlIHN0cmluZ2VudCB0aHJlc2hvbGQgcGFyYW1ldGVyIHJlbW92ZWQgU29zMSBmcm9tIHRoZSBkYXRhc2V0LiBTb3MxIGlzIGludm9sdmVkIHRvZ2V0aGVyIHdpdGggU3RhdDVhL2IgaW4gbW9zdCBvZiB0aGUgZW5yaWNoZWQgcGF0aHdheXMgaW4gdGhlIGxlc3Mgc3RyaW5nZW50IGRhdGFzZXQuIFRoZSAoUmFzLVJhZi0pIE1BUEsgcGF0aHdheSBpcyBwYXJ0bHkgcmVndWxhdGVkIGJ5IFNvczEsIG5vcm1hbGx5IGFjdGluZyBhcyBndWFuaW4gbnVjbGVvdGlkZSBleGNoYW5nZSBmYWN0b3IgW3Vwb24gUmFzXShodHRwczovL2RvaS5vcmcvMTAuMTA4My9qY2IuMjAwMTAzMTQ2KS4gUGhvc3Bob3J5bGF0aW9uIG9mIHNwZWNpZmljIFNlcmluIHJlc2lkdWVzIGhhdmUgYSBkZWFjdGl2YXRpbmcgZWZmZWN0IG9uIFNvczEgYW5kIGl0IGFjdHMgYXMgbmVnYXRpdmUgcmVndWxhdG9yIG9uIHRoZSBbd2hvbGUgTUFQSyBwYXRod2F5XShodHRwczovL2RvaS5vcmcvMTAuMTA0Mi9CSjIwMTIwOTM4KSwgYSBwYXRod2F5IG5vcm1hbGx5IGFzc29jaWF0ZWQgd2l0aCBbcHJvbW90aW5nIGRpZmZlcmVudGlhdGlvbl0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMDIvamNwLjI4MzM0KS4gU29zMSBpcyBhbHNvIGludm9sdmVkIGluIHRoZSBtVE9SIHBhdGh3YXksIHRvZ2V0aGVyIHdpdGggQWt0MXMxIChzdWJ1bml0IG9mIG1UT1JDMSksIGJvdGggYXJlIGZvdW5kIGluIHRoZSBsZXNzIHN0cmluZ2VudCBzdWIgbmV0d29yayBidXQgbm90IHRoZSBtb3JlIHN0cmluZ2VudCBvbmUuCgogICAgIVttVE9SLXBhdGh3YXkgd2l0aCBBa3QxczEgKFBSQVM0MCkgYW5kIFNvczEgbWFya2VkIGluIHBpbmsgZnJvbSBLRUdHLCBlbnRyeSBbbW11MDQxNTBdKGh0dHBzOi8vd3d3LmtlZ2cuanAvcGF0aHdheS9tbXUwNDE1MCkuXShpbWFnZXMvbVRPUl9wYXRod2F5LnBuZykKCi0gICBVbmRlciB0aGVzZSBiaW9sb2dpY2FsIGNpcmN1bXN0YW5jZXMgdGhlc2UgZmluZGluZ3MgY2FuIGJlIGNvdW50ZWQgYXMgdmFsaWQgYW5kIGFyZSBvYmplY3RzIGZvciBmdXJ0aGVyIGludmVzdGlnYXRpb25zLCB3aGlsZSBvdGhlciBoaXRzIGluIHRoZSBsZXNzIHN0cmluZ2VudCBkYXRhIHNldCBtYXkgYmUgZm91bmQgYXMgZmFsc2UgcG9zaXRpdmVzLiBUaGlzIHdhcyBhIHZlcnkgZ29vZCBleGFtcGxlIG9mIHRoZSB0cmFkZS1vZiBlbmNvdW50ZXJlZCBieSB0aHJlc2hvbGQgc2V0dGluZ3MgdGhhdCBtdXN0IGJlIGNvbnRyb2xsZWQgdGhvcm91Z2ggdGhlIGRhdGEgYW5hbHlzaXMuCgojIyMjIENvbmNsdXNpb24KCi0gICBNYW55IGNhbmNlcnMgaW52b2x2ZWQgcGF0aHdheXMgYXJlIGFsc28gYWN0aXZhdGVkIHRvIGVuc3VyZSBzdGVtbmVzcyBpbiBub24tZGlmZmVyZW50aWF0ZWQgbXVzY2xlIG1vdXNlIGNlbGxzIHVwb24gZGlmZmVyZW50aWF0aW9uIHN0aW11bGkuCi0gICBNYWpvciB0YXJnZXRzIGZvciBmdXJ0aGVyIGludmVzdGlnYXRpb25zIGFyZSBKQUstU1RBVCBwYXRod2F5IHByb3RlaW5zIGFuZCBTb3MxIGFuZCBBa3QxczEgd2l0aCB0aGUgbVRPUi0gYW5kIE1BUEstcGF0aHdheS4gRXNwZWNpYWxseSBpZGVudGlmaWNhdGlvbiBvZiBwaG9zcGhvcnlsYXRpb24gc2l0ZXMgaW4gdGhlIHByb3RlaW4gYW5kIGV4cGVyaW1lbnRzIHdpdGggZGlmZmVyZW50IGRpZmZlcmVudGlhdGlvbiBpbmhpYml0b3JzIHRvIGVuc3VyZSB1bnNwZWNpZmljIGFjdGl2YXRpb24gb2Ygc3RlbW5lc3MgcHJvdGVjdGluZyBwYXRod2F5cyBvciBpZGVudGlmaWNhdGlvbiBvZiBhbHRlcm5hdGl2ZWx5IGFjdGl2YXRlZCBwYXRod2F5cyBjb3VsZCBwcm92aWRlIG1vcmUgaW5zaWdodHMuCi0gICBBbHNvLCBwb3NzaWJseSBhIHJlcHJvZHVjdGlvbiBvZiB0aGUgZGF0YXNldCBjb250YWluaW5nIG1vcmUgc2FtcGxlcyB0byBpZGVudGlmeSB3aXRoIGEgaGlnaGVyIHNlY3VyaXR5IHRoZSBlbGV2YXRpb24gb2YgaW52b2x2ZWQgcHJvdGVpbnMgYW5kIGFsc28gcmVwcm9kdWN0aW9uIGluIGRpZmZlcmVudCBjZWxsIGxpbmVzIHRvIGVuc3VyZSB0aGF0IHRoZSBvYnNlcnZlZCBlZmZlY3RzIGFyZSBzdGVtbmVzcyByZWxhdGVkIGFuZCBub3QgY2VsbCBsaW5lIHJlbGF0ZWQgd291bGQgYmUgaW50ZXJlc3RpbmcgcmVzZWFyY2ggdGFyZ2V0cy4gU2luY2UgdGhlIGJpb2luZm9ybWF0aWMgcGlwZWxpbmUgaXMgaW4gcGxhY2UsIHRoZSBhbmFseXNpcyBjb3VsZCBiZSBjb25kdWN0ZWQgcXVpY2tseS4KCiMjIyMgUmVwcm9kdWNpYmlsaXR5Ci0gICBUaGlzIHByb2plY3QgaGFzIGEgW0dpdEh1YiByZXBvc2l0b3J5XShodHRwczovL2dpdGh1Yi5jb20vUnVtb2lzdGVpbkthcnRlbnNwaWVsL3Bob3NwaG9wcm90ZW9taWNzLmdpdCkgYW5kIHRoZSBSbm90ZWJvb2sgaXMgd3JpdHRlbiBzbyB0aGF0IGl0IGNhbiBiZSBleGVjdXRlZCB3aXRoIHRoZSBkb3dubG9hZGVkIHJlcG9zaXRvcnkuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo=